﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;

namespace LowLevelGraphics.Filter.Colors
{
    public enum MODE
    {
        ADD,
        SUBTRACT,
        MULTIPLY,
        DIVIDE,
        MODULO,

        AND,
        OR,
        XOR,

        MAXIMUM,
        MINIMUM,
        DIFFERENCE
    } 

    public class ChannelMath : BaseImageFilter
    {
        protected int[] m_aChannel = new int[2];

        protected MODE m_Mode = MODE.ADD;

        public ChannelMath(int _nChannel1, int _nChannel2)
        {
            m_aChannel[0] = _nChannel1;
            m_aChannel[1] = _nChannel2;
        }

        /// <summary>
        /// used to clone this instance
        /// </summary>
        /// <param name="_channelMath"></param>
        internal ChannelMath(ChannelMath _channelMath)
        {
            m_aChannel = _channelMath.m_aChannel;
        }

        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {
            int nWidth = _bitmap.Width;
            int nHeight = _bitmap.Height;

            for (int y = 0; y < nHeight; y++)
            {
                for (int x = 0; x < nWidth; x++)
                {
                    Color color = _bitmap.GetPixel(x, y);
                    int[] a = new int[3] { color.R, color.G, color.B };

                    int nResult = -1;
                    switch (m_Mode)
                    {
                        case MODE.ADD:
                            nResult = a[m_aChannel[0]] + a[m_aChannel[1]];
                            break;

                        case MODE.SUBTRACT:
                            nResult = a[m_aChannel[0]] - a[m_aChannel[1]];
                            break;

                        case MODE.DIVIDE:
                            nResult = a[m_aChannel[0]] / a[m_aChannel[1]];
                            break;

                        case MODE.MODULO:
                            nResult = a[m_aChannel[0]] % a[m_aChannel[1]];
                            break;

                        case MODE.AND:
                            nResult = a[m_aChannel[0]] & a[m_aChannel[1]];
                            break;

                        case MODE.OR:
                            nResult = a[m_aChannel[0]] | a[m_aChannel[1]];
                            break;

                        case MODE.XOR:
                            nResult = a[m_aChannel[0]] ^ a[m_aChannel[1]];
                            break;

                        case MODE.MINIMUM:
                            nResult = Math.Min(a[m_aChannel[0]], a[m_aChannel[1]]);
                            break;

                        case MODE.MAXIMUM:
                            nResult = Math.Max(a[m_aChannel[0]], a[m_aChannel[1]]);
                            break;

                        case MODE.DIFFERENCE:
                            nResult = Math.Abs(a[m_aChannel[0]] - a[m_aChannel[1]]);
                            break;

                    }

                    _bitmap.SetGrayPixel(x, y, nResult);
                }
            }
            return _bitmap;
        }

        public int[] Channel
        {
            get { return m_aChannel; }
            set { m_aChannel = value; }
        }

        /// <summary>
        /// Clones this instance
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new ChannelMath(this);
        }
    }
}
